import { reactive, ref } from 'vue';
import axios from '@/config/axios/index.ts';
import { VxeUI } from 'vxe-pc-ui';
import { UploadInst, UploadProps, UploadSettledFileInfo } from 'naive-ui';
import type { JsonResultProps } from '#/JsonResult.d.ts';
import type { WaitForUpLoadFileProps } from '#/FileUpDownLoad.d.ts';
import type { AxiosProgressEvent } from 'axios';
import type {
	CommonFileUpDownLoadProps
} from '#/src/components/customComponents/fileUpLoad/modal/ModalFileUpLoadListProps.d.ts';
import { clone } from 'xe-utils';
const useUpLoadHooks = (props: CommonFileUpDownLoadProps) => {
	// --------------------------------------------------------------------------------
	// 待上传列表
	const waitForUploadFileList = reactive<Array<WaitForUpLoadFileProps>>([]);
	//---------------------------------------------------上传类-----------------------------------------------------------
	// 上传列表引用
	const upLoadRef = ref<UploadInst>();
	// 上传配置
	const upLoadConfig: UploadProps = reactive({
		accept         : '',
		action         : '',
		defaultUpload  : false,
		directory      : false,
		directoryDnd   : true,
		multiple       : true,
		showFileList   : false,
		onBeforeUpload : (options: {
			file: UploadSettledFileInfo,
			fileList: UploadSettledFileInfo[]
		}) => beforeUpload(options)
	});
	// -------------------------------------------------------------------------------------------
	const setAccept = async (accept?: string) => {
		upLoadConfig.accept = accept;
	};
	const clearWaitForUploadFileList = async () => {
		// 先检查所有的文件,看是否存在控制器
		for (const file of waitForUploadFileList) {
			// 如果控制器存在,则它正在上传中,需要逐一终止请求
			file.controller?.abort();
		}
		// 最后将待上传列表清空
		waitForUploadFileList.length = 0;
	};
	const cleanData = async () => {
		await clearWaitForUploadFileList();
		// Object.assign(waitForUploadFileList, []);
	};
	/**
	 * 删除待上传列表中的一行数据
	 */
	const spliceRow = async (index: number) => {
		// 存在控制器则终止请求
		waitForUploadFileList[index].controller?.abort();
		// 删除待上传列表中的内容
		waitForUploadFileList.splice(index, 1);
	};
	// -------------------------------------------------------------------------------------------
	/**
	 * 上传前检测
	 * @param options
	 */
	const beforeUpload = async (options: {
		file: UploadSettledFileInfo,
		fileList: UploadSettledFileInfo[]
	}): (Promise<boolean | void>) => {
		const rawFile = options.file.file as File;
		// 空文件检测
		if (0 >= rawFile.size) {
			await VxeUI.modal.message({
				content : `${rawFile.name} 内容为空`,
				status  : 'warning',
				id      : `fileSizeIsEmptyMessage_${rawFile.name}`
			});
			return false;
		}
		// 文件过大检测
		if (rawFile.size > props.fileUpLoad.maxSize) {
			await VxeUI.modal.message({
				content : `${rawFile.name} 文件太大`,
				status  : 'warning',
				id      : `fileSizeTooLargeMessage_${rawFile.name}`
			});
			return false;
		}
		// 文件类型检测
		const fileExtensionSplit = rawFile.name.split('.');
		const fileExtension = fileExtensionSplit[fileExtensionSplit.length - 1];
		if (!props.fileUpLoad.format.includes(fileExtension)) {
			await VxeUI.modal.message({
				content : `${rawFile.name} 的文件类型不匹配`,
				status  : 'warning',
				id      : `fileExtensionNotMatchMessage_${rawFile.name}`
			});
			return false;
		}
		waitForUploadFileList.push({
			processing    : false,
			name          : rawFile.name,
			size          : rawFile.size,
			fileExtension : fileExtension,
			file          : rawFile,
			percent       : 0,
			color         : '#409EFF',
			status        : 'default',
			controller    : null
		});
		if (props.fileUpLoad.onAfterValidate) {
			props.fileUpLoad.onAfterValidate(options, waitForUploadFileList);
		}
		// 返回false,就不会自动提交
		return false;
	};
	/**
	 * 处理用户定义的上传前事件
	 */
	const handleBeforeUpload = async () => {
		// 判断外部组件是否传递了onBeforeUpload方法
		if (props.fileUpLoad.onBeforeUpload) {
			// 传递了则调用
			// 异步传输时,onBeforeUpload方法每次上传前都会执行
			props.fileUpLoad.onBeforeUpload();
		}
	};
	/**
	 * 处理用户定义的上传后事件
	 */
	const handleAfterUpload = async () => {
		// 判断外部组件是否传递了onAfterUpload方法
		if (props.fileUpLoad.onAfterUpload) {
			// 传递了则调用
			// 异步传输时,onAfterUpload方法每次成功上传都会执行
			props.fileUpLoad.onAfterUpload();
		}
	};
	/**
	 * 开始上传
	 * @returns {Promise<void>}
	 */
	const submitUpload = async (): Promise<void> => {
		// 判断待上传列表是否为空
		if (!waitForUploadFileList.length) {
			await VxeUI.modal.message({
				content : '请先选择一些文件!',
				status  : 'warning',
				id      : `failedMessage`
			});
			return;
		}
		await handleBeforeUpload();
		const handleArr = [];
		for (let i = waitForUploadFileList.length - 1; 0 <= i; i--) {
			const index = clone(i);
			const file = waitForUploadFileList[index];
			// 将得到的文件流添加到FormData对象
			const data: FormData = new FormData();
			data.append(props.fileUpLoad.field, file.file!, file.name);
			// 添加用户自定义表单属性
			for (const dataKey in props.fileUpLoad.params) {
				if (Object.prototype.hasOwnProperty.call(props.fileUpLoad.params, dataKey)) {
					data.append(dataKey, props.fileUpLoad.params[dataKey]);
				}
			}
			handleArr.push(asyncBatchUpload(file, data));
		}
		Promise.all(handleArr).then(() => {
			handleAfterUpload();
		});
	};
	/**
	 * 异步批量上传<br/>
	 * 异步的批量上传,它的上传事件是会执行多次的<br/>
	 * 即:<br/>
	 * onBeforeUpload1<br/>
	 * 上传1<br/>
	 * onAfterUpload1<br/>
	 * onBeforeUpload2<br/>
	 * 上传2<br/>
	 * onAfterUpload2<br/>
	 * onBeforeUpload3<br/>
	 * 上传3<br/>
	 * onAfterUpload3
	 */
	const asyncBatchUpload = async (file: any, data: any) => {
		Object.assign(file, {
			controller : new AbortController(),
			processing : true,
			color      : '#409EFF',
			status     : 'info'
		});
		return new Promise((resolve, reject): void => {
			axios<any, JsonResultProps<any>, any>({
				timeout : props.fileUpLoad.timeout,
				method  : 'POST',
				url     : props.fileUpLoad.url,
				headers : { ...props.fileUpLoad.headers, 'Content-Type' : 'multipart/form-data' },
				data    : data,
				signal  : file.controller!.signal,
				// 使用axios自带的进度条事件
				onUploadProgress : async (progressEvent: AxiosProgressEvent) => {
					// 多文件合并进度条和单文件进度条的写法不同
					// 多文件合并在一起上传只会有总进度条,所以下列把多个文件的进度条统一设置
					if (progressEvent.total) {
						// 进度条算法
						file.percent = Math.round(parseFloat(progressEvent.progress!.toString()) * 100);
					}
				}
			}).then(async (jsonResult: JsonResultProps<any>) => {
				if (jsonResult.status) {
					Object.assign(file, {
						processing : false,
						color      : '#69EE2B',
						status     : 'success'
					});
					resolve(jsonResult);
				} else {
					Object.assign(file, {
						processing : false,
						color      : '#FF8467',
						status     : 'error'
					});
					await VxeUI.modal.message({
						content : jsonResult.msg,
						status  : 'warning',
						id      : `failedMessage`
					});
					reject(jsonResult.msg);
				}
			}).catch(error => {
				Object.assign(file, {
					processing : false,
					color      : '#FF8467',
					status     : 'error'
				});
				console.error(error);
				if ('canceled' === error.message) {
					VxeUI.modal.message({
						content : '请求已取消',
						status  : 'warning',
						id      : 'errorMessage'
					});
				} else {
					VxeUI.modal.message({
						content : `${file.name}因未知异常上传失败,请稍后再试`,
						status  : 'error',
						id      : 'errorMessage'
					});
				}
				reject(error);
			});
		});
	};
	//---------------------------------------------------表格类-----------------------------------------------------------
	return {
		upLoadRef,
		waitForUploadFileList,
		upLoadConfig,
		setAccept,
		clearWaitForUploadFileList,
		cleanData,
		beforeUpload, submitUpload,
		handleBeforeUpload, handleAfterUpload,
		asyncBatchUpload,
		spliceRow
	};
};
export default useUpLoadHooks;